package com.allen.study.application.service;

import com.allen.study.application.api.assembler.LeaveApplyApproveDTOAssembler;
import com.allen.study.application.api.assembler.LeaveApplyDTOAssembler;
import com.allen.study.application.api.request.LeaveApplyApproveRequest;
import com.allen.study.application.api.request.LeaveApplyCreateRequest;
import com.allen.study.application.api.request.LeaveApplyQueryRequest;
import com.allen.study.application.api.request.LeaveApplyUpdateRequest;
import com.allen.study.application.api.response.LeaveApplyQueryResponse;
import com.allen.study.application.api.response.LeaveApplyResponse;
import com.allen.study.application.repository.ILeaveApplyReadModelRepo;
import com.allen.study.common.base.ApiPageResponse;
import com.allen.study.common.base.ApiResponse;
import com.allen.study.common.base.DomainResponse;
import com.allen.study.common.base.Pagination;
import com.allen.study.common.constants.LeaveApplyConstants;
import com.allen.study.common.utils.CamundaUtils;
import com.allen.study.domain.entity.LeaveApply;
import com.allen.study.domain.entity.LeaveApplyApprove;
import com.allen.study.domain.service.LeaveApplyService;
import lombok.AllArgsConstructor;
import org.camunda.bpm.engine.history.HistoricProcessInstance;
import org.camunda.bpm.engine.task.Task;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 请假申请表应用服务
 *
 * @author AllenSun
 * @since 2025-04-23 20:46
 */
@Service
@AllArgsConstructor
public class LeaveApplyAppService {

    /**
     * 请假申请表领域服务
     */
    private final LeaveApplyService leaveApplyService;

    /**
     * 请假申请表读模型资源库
     */
    private final ILeaveApplyReadModelRepo leaveApplyReadModelRepo;

    /**
     * 请假申请表数据传输对象转换器
     */
    private final LeaveApplyDTOAssembler leaveApplyDTOAssembler;
    private final LeaveApplyApproveDTOAssembler leaveApplyApproveDTOAssembler;

    /**
     * 创建请假申请表
     *
     * @param createRequest 请假申请表创建对象
     * @return 响应结果
     */
    public ApiResponse<Void> create(LeaveApplyCreateRequest createRequest) {
        // 请假申请表创建对象 转成 请假申请表实体
        LeaveApply leaveApply = leaveApplyDTOAssembler.assembler(createRequest);
        // 调用创建请假申请表领域服务
        DomainResponse<Void> domainResponse = leaveApplyService.create(leaveApply);
        // 领域响应结果转成API响应结果
        return ApiResponse.valueOf(domainResponse);
    }

    /**
     * 根据主键删除请假申请表
     *
     * @param leaveApplyId 请假申请表主键
     * @return 响应结果
     */
    public ApiResponse<Void> deleteById(Long leaveApplyId) {
        // 调用删除请假申请表领域服务
        DomainResponse<Void> domainResponse = leaveApplyService.deleteById(leaveApplyId);
        // 领域响应结果转成API响应结果
        return ApiResponse.valueOf(domainResponse);
    }

    /**
     * 根据主键更新请假申请表
     *
     * @param leaveApplyId 请假申请表主键
     * @param updateRequest 请假申请表更新对象
     * @return 响应结果
     */
    public ApiResponse<Void> updateById(Long leaveApplyId, LeaveApplyUpdateRequest updateRequest) {
        // 请假申请表更新对象 转成 请假申请表实体
        LeaveApply leaveApply = leaveApplyDTOAssembler.assembler(updateRequest);
        // 设置主键
        leaveApply.setId(leaveApplyId);
        // 调用更新请假申请表领域服务
        DomainResponse<Void> domainResponse = leaveApplyService.updateById(leaveApply);
        // 领域响应结果转成API响应结果
        return ApiResponse.valueOf(domainResponse);
    }

    /**
     * 根据主键查询请假申请表详情
     *
     * @param leaveApplyId 请假申请表主键
     * @return 响应结果
     */
    public ApiResponse<LeaveApplyResponse> queryById(Long leaveApplyId) {
        // 根据主键查询请假申请表
        DomainResponse<LeaveApply> domainResponse = leaveApplyService.queryById(leaveApplyId);
        // 领域响应结果转成API响应结果
        return ApiResponse.valueOf(domainResponse, leaveApplyDTOAssembler::toResponse);
    }

    /**
     * 分页查询请假申请表
     *
     * @param pagination   分页
     * @param queryRequest 请假申请表查询对象
     * @return 响应结果
     */
    public ApiPageResponse<LeaveApplyQueryResponse> query(Pagination pagination, LeaveApplyQueryRequest queryRequest) {
        // 调用请假申请表读模型资源库分页查询
        List<LeaveApplyQueryResponse> list = leaveApplyReadModelRepo.query(pagination, queryRequest);
        return ApiPageResponse.ok(pagination, list);
    }

    /**
     * 获取我的提交申请
     * @MethodName: queryMyApply
     * @Author: AllenSun
     * @Date: 2025/4/25 00:00
     */
    public ApiPageResponse<LeaveApplyQueryResponse> queryMyApply(Pagination pagination, LeaveApplyQueryRequest queryRequest) {

        // 根据用户id从本地记录表查询记录
        queryRequest.setEmployeeId(LeaveApplyConstants.employeeId);
        // 调用请假申请表读模型资源库分页查询
        List<LeaveApplyQueryResponse> list = leaveApplyReadModelRepo.query(pagination, queryRequest);
        Set<String> myInstanceIds =
                Optional.ofNullable(list).orElse(new ArrayList<>()).stream().map(LeaveApplyQueryResponse::getId).collect(Collectors.toSet());
        // 遍历扩充信息，包括：审批状态，审批时间，当前的审批节点
        // 首先查询所有我提交的申请流程案例，根据流程定义key和发起人id
        List<HistoricProcessInstance> processInstancesByUser =
                CamundaUtils.getProcessInstancesByInstanceIds(myInstanceIds,
                LeaveApplyConstants.employeeId);
        // TODO 补充信息

        return ApiPageResponse.ok(pagination, list);
    }

    /**
     * 获取我待审核的任务
     * @MethodName: queryToApprovelApply
     * @Author: AllenSun
     * @Date: 2025/4/25 00:01
     */
    public ApiPageResponse<LeaveApplyQueryResponse> queryToApprovelApply(Pagination pagination, LeaveApplyQueryRequest queryRequest) {
        // 首先查询所有我待审核的流程案例，根据流程定义key和发起人id
        List<Task> taskList =
                CamundaUtils.getPendingProcessInstances(LeaveApplyConstants.processDefinitionKey,
                LeaveApplyConstants.employeeId);
        List<String> myInstanceIds =
                Optional.ofNullable(taskList).orElse(new ArrayList<>()).stream().map(Task::getProcessInstanceId).collect(Collectors.toList());
        queryRequest.setProcessInstanceIds(myInstanceIds);
        // 调用请假申请表读模型资源库分页查询
        List<LeaveApplyQueryResponse> list = leaveApplyReadModelRepo.query(pagination, queryRequest);
        return ApiPageResponse.ok(pagination, list);
    }

    /**
     * 获取我待审核的任务
     * @MethodName: queryToApprovelApply
     * @Author: AllenSun
     * @Date: 2025/4/25 00:01
     */
    public ApiPageResponse<LeaveApplyQueryResponse> queryApproveledApply(Pagination pagination, LeaveApplyQueryRequest queryRequest) {
        // 首先查询所有我已审核的流程案例，根据流程定义key和发起人id
        List<HistoricProcessInstance> instanceList =
                CamundaUtils.getParticipatedProcessInstances(LeaveApplyConstants.processDefinitionKey,
                        LeaveApplyConstants.employeeId);
        List<String> myInstanceIds =
                Optional.ofNullable(instanceList).orElse(new ArrayList<>()).stream().map(HistoricProcessInstance::getId).collect(Collectors.toList());
        queryRequest.setProcessInstanceIds(myInstanceIds);
        // 调用请假申请表读模型资源库分页查询
        List<LeaveApplyQueryResponse> list = leaveApplyReadModelRepo.query(pagination, queryRequest);
        return ApiPageResponse.ok(pagination, list);
    }


    public ApiResponse<LeaveApplyResponse> apply(LeaveApplyCreateRequest createRequest) {
        LeaveApply leaveApply = leaveApplyDTOAssembler.assembler(createRequest);
        // 根据主键查询请假申请表
        DomainResponse<LeaveApply> domainResponse = leaveApplyService.apply(leaveApply);
        // 领域响应结果转成API响应结果
        return ApiResponse.valueOf(domainResponse, leaveApplyDTOAssembler::toResponse);
    }

    public ApiResponse<Void> approve(LeaveApplyApproveRequest approveRequest) {
        LeaveApplyApprove leaveApplyApprove = leaveApplyApproveDTOAssembler.assembler(approveRequest);
        // 根据主键查询请假申请表
        DomainResponse<Void> domainResponse = leaveApplyService.approve(leaveApplyApprove);
        // 领域响应结果转成API响应结果
        return ApiResponse.ok();
    }

}
